package com.irdstudio.efp.esb.api.rest.ms;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Objects;

import javax.servlet.http.HttpServletRequest;

import com.irdstudio.efp.esb.common.constant.InstitutionEnums;
import com.irdstudio.efp.loan.common.LoanConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.irdstudio.basic.framework.core.base.FrameworkService;
import com.irdstudio.basic.framework.core.constant.BaseConstant;
import com.irdstudio.basic.framework.core.constant.EsbRetCodeStandard;
import com.irdstudio.basic.framework.core.exception.BizException;
import com.irdstudio.basic.framework.core.util.MessageRuleCheckUtil;
import com.irdstudio.basic.framework.core.util.TraceUtil;
import com.irdstudio.basic.framework.core.util.ValidationUtils;
import com.irdstudio.efp.esb.api.bean.zzd.ReqNoticeOfResultBean;
import com.irdstudio.efp.esb.api.bean.zzd.RespNoticeOfResultBean;
import com.irdstudio.efp.esb.api.common.EsbRespServiceBeanCreator;
import com.irdstudio.efp.esb.api.common.SDicServerConstant;
import com.irdstudio.efp.esb.api.util.SDicMappingServer;
import com.irdstudio.efp.esb.common.constant.EsbBizEnums;
import com.irdstudio.efp.esb.common.constant.EsbSysHeadEnums;
import com.irdstudio.efp.esb.common.server.req.EsbReqServiceBean;
import com.irdstudio.efp.esb.common.server.resp.EsbRespServiceBean;
import com.irdstudio.efp.loan.service.facade.AccLoanService;
import com.irdstudio.efp.loan.service.vo.AccLoanVO;
import com.irdstudio.efp.nls.service.facade.NlsApplyInfoService;
import com.irdstudio.efp.nls.service.vo.NlsApplyInfoVO;

@RestController
@RequestMapping("/esb")
public class NoticeOfResultController implements FrameworkService {

	private static Logger logger = LoggerFactory.getLogger(NoticeOfResultController.class);

	@Autowired
	@Qualifier("nlsApplyInfoService")
	private NlsApplyInfoService nlsApplyInfoService;
	@Autowired
	@Qualifier("accLoanService")
	private AccLoanService accLoanService;

	// 马上产品-银行出资比例
	@Value("${ms.financial.bankpProportion}")
	private String bankpProportion;

	
	/**
	 * 获取ESB请求对象，校验 ESB请求系统头和请求应用头对象
	 * 
	 * @param request
	 *            请求对象集合
	 * @return
	 * @author huangwb
	 * @since 2019年1月20日 下午1:28:08
	 * @version 1.0
	 */
	@ModelAttribute("esbReqServiceBean")
	public EsbReqServiceBean getReqEsbHeadBean(HttpServletRequest request) {
		logger.info("获取ESB请求对象，校验 ESB请求系统头和请求应用头对象开始");
		EsbReqServiceBean esbReqServiceBean = (EsbReqServiceBean) request.getAttribute("esbReqServiceBean");
		return esbReqServiceBean;
	}

	/**
	 * 获取ESB请求对象，校验 ESB请求体对象
	 * 
	 * @param request
	 *            请求对象集合
	 * @return
	 * @author liyakui
	 * @since 2019年1月20日 下午1:31:14
	 * @version 1.0
	 */
	@ModelAttribute("reqNoticeOfResultBean")
	public ReqNoticeOfResultBean getReqEsbBodyBean(HttpServletRequest request) {
		logger.info("获取放款结果通知请求对象，校验放款结果通知请求体对象开始");
		String esbReqBody = (String) request.getAttribute("esbReqBody");
		return JSONObject.parseObject(esbReqBody, ReqNoticeOfResultBean.class);
	}

	
	
	/**
	 * 放款结果通知接口
	 * 1.1: qiuyf:2019年3月8日 上午9:44:51: 统一esb返回码信息<br>
	 * @param reqNoticeOfResultBean
	 * @return
	 * @throws Exception
	 * @author liyakui
	 * @since 2018年12月29日 上午11:41:13
	 * @date 2019年3月8日 上午9:44:51
	 * @version 1.0，1.1
	 */
	@PostMapping("/SERVICE_30220007_02")
	public EsbRespServiceBean doRecv(@Validated @ModelAttribute("esbReqServiceBean") EsbReqServiceBean esbReqServiceBean, BindingResult br1,
			@Validated @ModelAttribute("reqNoticeOfResultBean") ReqNoticeOfResultBean reqNoticeOfResultBean, BindingResult br2, Exception exception) {
		try {

			// 1.通过切面校验进件申请参数是否正确，如不正确则返回错误信息
			if (Objects.nonNull(exception)) {
				throw exception;
			}
			// 校验日期时间
			MessageRuleCheckUtil.checkDate("交易时间", reqNoticeOfResultBean.getTransTm(), "yyyy-MM-dd HH:mm:ss", EsbRetCodeStandard.JKYDCSJYBTG.getValue());
			// 放款金额检验
			boolean flag = ValidationUtils.isCurrency(reqNoticeOfResultBean.getDistrAmt());
			if (!flag) {
				logger.debug("放款金额格式错误！ 组装报文返回**************");
				return EsbRespServiceBeanCreator.buildesbRespServiceBean(esbReqServiceBean,
						JSON.toJSONString(buildRespNoticeOfResultBean(EsbRetCodeStandard.JKYDCSJYBTG.getValue(), "放款金额格式错误！",reqNoticeOfResultBean.getTxnFlowNo())),
						EsbSysHeadEnums.RetStEnum.SUCCESS.getCode(), EsbRetCodeStandard.JKYDCSJYBTG.getValue(), "放款金额格式错误！");
			}
			String distrSt = SDicMappingServer.getLocalSysDicVal(SDicServerConstant.LOAN_STATUS, reqNoticeOfResultBean.getDistrSt());// 放款状态转换
			
			// 2.获取交易流水号或订单号
			logger.info("交易流水号[" + reqNoticeOfResultBean.getTxnFlowNo() + "]放款结果通知开始!");

			// 1.根据交易流水号查询网贷申请基本表
			NlsApplyInfoVO nlsApplyInfoVo = new NlsApplyInfoVO();
			nlsApplyInfoVo.setApplySeq(reqNoticeOfResultBean.getTxnFlowNo());
			nlsApplyInfoVo = nlsApplyInfoService.queryByPk(nlsApplyInfoVo);
			if (nlsApplyInfoVo != null) {
				// 判断是否正常审批通过
				if (!BaseConstant.NLS_APPLY_STATE_02.equals(nlsApplyInfoVo.getNlsApplyState())) {
					logger.debug("网贷审批不通过,不应放款！组装报文返回**************");
					return EsbRespServiceBeanCreator.buildesbRespServiceBean(esbReqServiceBean,
							JSON.toJSONString(buildRespNoticeOfResultBean(EsbRetCodeStandard.YWLJCLYC.getValue(), "网贷审批不通过,不应放款！",reqNoticeOfResultBean.getTxnFlowNo())),
							EsbSysHeadEnums.RetStEnum.SUCCESS.getCode(), EsbRetCodeStandard.YWLJCLYC.getValue(), "网贷审批不通过,不应放款！");
				}
				// 判断是否重复发起放款结果通知
				String dnSts = nlsApplyInfoVo.getDnSts();
				if (BaseConstant.DN_STS_0.equals(dnSts)) {
					// 已经放款失败，勿重发
					// 5.组装返回报文
					logger.debug("已经放款失败，勿重发！");
					return EsbRespServiceBeanCreator.buildesbRespServiceBean(esbReqServiceBean,
							JSON.toJSONString(buildRespNoticeOfResultBean(EsbRetCodeStandard.YWLJCLYC.getValue(), "已经放款失败，勿重发！", reqNoticeOfResultBean.getTxnFlowNo())),
							EsbSysHeadEnums.RetStEnum.SUCCESS.getCode(), EsbRetCodeStandard.YWLJCLYC.getValue(), "已经放款失败，勿重发！");
				} else if (BaseConstant.DN_STS_1.equals(dnSts)) {
					// 已经成功放款，勿重发
					// 5.组装返回报文
					logger.debug("已经成功放款，勿重发");
					return EsbRespServiceBeanCreator.buildesbRespServiceBean(esbReqServiceBean,
							JSON.toJSONString(buildRespNoticeOfResultBean(EsbRetCodeStandard.YWLJCLYC.getValue(), "已经成功放款，勿重发",reqNoticeOfResultBean.getTxnFlowNo())),
							EsbSysHeadEnums.RetStEnum.SUCCESS.getCode(), EsbRetCodeStandard.YWLJCLYC.getValue(), "已经成功放款，勿重发");

				} else if (BaseConstant.DN_STS_2.equals(dnSts)) {
					// 马上已经全额放款，勿重发
					// 5.组装返回报文
					logger.debug("马上已经全额放款，勿重发");
					return EsbRespServiceBeanCreator.buildesbRespServiceBean(esbReqServiceBean,
							JSON.toJSONString(buildRespNoticeOfResultBean(EsbRetCodeStandard.YWLJCLYC.getValue(), "马上已经全额放款，勿重发",
									reqNoticeOfResultBean.getTxnFlowNo())),
							EsbSysHeadEnums.RetStEnum.SUCCESS.getCode(), EsbRetCodeStandard.YWLJCLYC.getValue(), "马上已经全额放款，勿重发");
				} else {
					nlsApplyInfoVo.setDnSts(distrSt);// 更新状态
					nlsApplyInfoVo.setAmountOfLoan(reqNoticeOfResultBean.getDistrAmt());// 放款金额
					nlsApplyInfoVo.setLastModifyTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));// 修改更新时间
					nlsApplyInfoService.updateByPk(nlsApplyInfoVo);
					// 4.若放款成功向借据表插入一条借据信息
					if (BaseConstant.DN_STS_1.equals(distrSt)) {
						AccLoanVO accLoanVo = new AccLoanVO();
						accLoanVo.setBillNo(reqNoticeOfResultBean.getTxnFlowNo());
						accLoanVo.setCusId(nlsApplyInfoVo.getCusId());
						accLoanVo.setCusName(nlsApplyInfoVo.getCusName());
						accLoanVo.setPrdId(nlsApplyInfoVo.getPrdId());
						accLoanVo.setPrdCode(nlsApplyInfoVo.getPrdCode());
						accLoanVo.setPrdName(nlsApplyInfoVo.getPrdName());
						accLoanVo.setContNo(reqNoticeOfResultBean.getTxnFlowNo());// 合同号

						// 2019/10/31 modify by ludayong 借据金额按银行出资比例赋值
						BigDecimal bigDecDistrAmt = new BigDecimal(reqNoticeOfResultBean.getDistrAmt() == null ? "0" : reqNoticeOfResultBean.getDistrAmt().toString());
						BigDecimal loanAmount= bigDecDistrAmt.multiply(new BigDecimal(bankpProportion));
						// 借据金额马上放款金额是整百，一般不会出现小数,但也按四舍五入处理
						loanAmount = loanAmount.setScale(2,BigDecimal.ROUND_HALF_UP);
						accLoanVo.setLoanAmount(loanAmount);// 借据金额
						accLoanVo.setLoanBalance(loanAmount);// 借据余额
                        // 2019/10/31 modify by ludayong 贷款到期日取马上用信接口-贷款到期日字段赋值
						accLoanVo.setLoanStartDate(nlsApplyInfoVo.getApplyDate());
						accLoanVo.setOrigExpiDate(nlsApplyInfoVo.getLoanDueDate());// 原到期日期
						accLoanVo.setLoanEndDate(nlsApplyInfoVo.getLoanDueDate());// 贷款到期日

						accLoanVo.setLoanTerm(new BigDecimal(nlsApplyInfoVo.getLoanTerm() == null ? "0" : nlsApplyInfoVo.getLoanTerm()));// 贷款期限
						accLoanVo.setLoadTermType(nlsApplyInfoVo.getLoanTermType());// 期限类型
						accLoanVo.setEnterAccount(nlsApplyInfoVo.getRecvAcctNo());// 放款账号
						// modify by ludayong 2019/11/21 【2019D1127】更新借据状态为出帐未确认
						accLoanVo.setAccountStatus(LoanConstant.TZZT_WQR);
						accLoanVo.setCreateTime(new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
						accLoanVo.setCurType(nlsApplyInfoVo.getLoanCcy());// 币种
						accLoanVo.setRepaymentMode(nlsApplyInfoVo.getRepayMethod());// 还款方式
						accLoanVo.setCertCode(nlsApplyInfoVo.getCertCode());
						accLoanVo.setCertType(nlsApplyInfoVo.getCertType());
						accLoanVo.setChannelCode(nlsApplyInfoVo.getChannelNo()); // 渠道编号
						accLoanVo.setApplySeq(nlsApplyInfoVo.getApplySeq());// 用信流水号
						// add by ludayong 2019/11/15 【数据权限】增加登记机构赋值
						// 登记机构
						accLoanVo.setInputBrId(InstitutionEnums.InstitutionEnum.GZYHZHYHZXSCTD2.getCode());
						accLoanService.insertAccLoan(accLoanVo);

						// 5.组装返回报文
						logger.debug("联合放款成功！");
						return EsbRespServiceBeanCreator.buildesbRespServiceBean(esbReqServiceBean,
								JSON.toJSONString(buildRespNoticeOfResultBean(EsbBizEnums.RetCodeEnum.SUCCESS.getVALUE(), "联合放款成功！", reqNoticeOfResultBean.getTxnFlowNo())),
								EsbSysHeadEnums.RetStEnum.SUCCESS.getCode(), EsbBizEnums.RetCodeEnum.SUCCESS.getVALUE(), "联合放款成功！");
					} else if (BaseConstant.DN_STS_0.equals(distrSt)) {
						// 5.组装返回报文
						logger.debug("放款失败！");
						return EsbRespServiceBeanCreator.buildesbRespServiceBean(esbReqServiceBean,
								JSON.toJSONString(buildRespNoticeOfResultBean(EsbBizEnums.RetCodeEnum.SUCCESS.getVALUE(), "放款失败！", reqNoticeOfResultBean.getTxnFlowNo())),
								EsbSysHeadEnums.RetStEnum.SUCCESS.getCode(), EsbBizEnums.RetCodeEnum.SUCCESS.getVALUE(), "放款失败！");
					} else if (BaseConstant.DN_STS_2.equals(distrSt)) {
						// 5.组装返回报文
						logger.debug("马上全额放款");
						return EsbRespServiceBeanCreator.buildesbRespServiceBean(esbReqServiceBean,
								JSON.toJSONString(buildRespNoticeOfResultBean(EsbBizEnums.RetCodeEnum.SUCCESS.getVALUE(), "马上全额放款", reqNoticeOfResultBean.getTxnFlowNo())),
								EsbSysHeadEnums.RetStEnum.SUCCESS.getCode(), EsbBizEnums.RetCodeEnum.SUCCESS.getVALUE(), "马上全额放款");
					}
				}

			} else {
				// 网贷申请表查询
				// 5.组装返回报文
				logger.debug("网贷基本申请表没有找到此条数据！");
				return EsbRespServiceBeanCreator.buildesbRespServiceBean(esbReqServiceBean,
						JSON.toJSONString(buildRespNoticeOfResultBean(EsbRetCodeStandard.JKYDCSJYBTG.getValue(), "网贷基本申请表没有找到此条数据！", reqNoticeOfResultBean.getTxnFlowNo())),
						EsbSysHeadEnums.RetStEnum.SUCCESS.getCode(), EsbRetCodeStandard.JKYDCSJYBTG.getValue(), "网贷基本申请表没有找到此条数据！");
			}
			return EsbRespServiceBeanCreator.buildesbRespServiceBean(esbReqServiceBean,
					JSON.toJSONString(buildRespNoticeOfResultBean(EsbBizEnums.RetCodeEnum.SUCCESS.getVALUE(), "交易成功",reqNoticeOfResultBean.getTxnFlowNo())),
					EsbSysHeadEnums.RetStEnum.SUCCESS.getCode(), EsbBizEnums.RetCodeEnum.SUCCESS.getVALUE(), "交易成功");

		} catch (BizException e) {
			logger.error("***********放款结果通知接口调用失败**************"+e.getMessage());
			return EsbRespServiceBeanCreator.buildesbRespServiceBean(esbReqServiceBean,
					JSON.toJSONString(buildRespNoticeOfResultBean(e.getErrorCode(), e.getMessage(),reqNoticeOfResultBean.getTxnFlowNo())),
					EsbSysHeadEnums.RetStEnum.FAILURE.getCode(), e.getErrorCode(), e.getMessage());
		} 
		catch (Exception e) {
			logger.error("***********放款结果通知接口调用失败**************"+e.getMessage());
			return EsbRespServiceBeanCreator.buildesbRespServiceBean(esbReqServiceBean,
					JSON.toJSONString(buildRespNoticeOfResultBean(EsbRetCodeStandard.OTHERS_EXCEPTION.getValue(), e.getMessage(),reqNoticeOfResultBean.getTxnFlowNo())),
					EsbSysHeadEnums.RetStEnum.FAILURE.getCode(), EsbRetCodeStandard.OTHERS_EXCEPTION.getValue(), e.getMessage());
		} finally {
			logger.info("交易流水号：[" + reqNoticeOfResultBean.getTxnFlowNo() + "]，放款结果通知结束!");
			TraceUtil.clear();
		}
		
	}

	/**
	 * 组织放款结果通知请求接口的返回对象
	 * 
	 * @param retStCd
	 *            返回状态码
	 * @param rtnMsg
	 *            返回信息
	 * @return
	 * @author liyakui
	 * @since 2019年1月20日 下午1:59:46
	 * @version 1.0
	 */
	private static RespNoticeOfResultBean buildRespNoticeOfResultBean(String retStCd, String rtnMsg, String txnFlowNo) {
		logger.debug("返回bean组装开始...流水号：" + txnFlowNo);
		RespNoticeOfResultBean respNoticeOfResultBean = new RespNoticeOfResultBean();
		respNoticeOfResultBean.setRetStCd(retStCd);
		respNoticeOfResultBean.setRtnMsg(rtnMsg);
		logger.debug("{*********返回bean组装结束！流水号:" + txnFlowNo + ",返回码:" + retStCd + ",返回信息:" + rtnMsg + "**********}");
		return respNoticeOfResultBean;
	}

}
